<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>依赖收集</title>
</head>

<body>
  <script>
    /**
 * 依赖收集
 * @authors Your Name (you@example.org)
 * @date    2019-11-26 10:34:20
 * @version 计算某个同学的岁数
 */



    let current = {
      year: 2019
    }

    let student = {
      born: 1991
    }

    let ageObj = {
      age: 0 // 初始岁数
    }

    defineReactive(current, 'year');

    defineReactive(student, 'born');

    defineComputed(ageObj, 'age', () => current.year - student.born, value => {

      console.log(`this student's aged is ${value}`);

    });





    // 标记当前正在求值的 computed 函数
    let Dep = null // 依赖
    function defineComputed(obj, key, computeFn, updateCallback) {

      // 封装供 reactive 收集的更新回调，以触发 computed 的更新事件
      const onDependencyUpdated = function () {
        // 在此调用 computeFn 计算出的值用于触发 computed 的更新事件
        // 供后续可能的 watch 等模块使用
        const value = computeFn()
        updateCallback(value)
      }

      Object.defineProperty(obj, key, {

        get() {
          console.log(111)
          // 标记当前依赖，供 reactive 收集
          Dep = onDependencyUpdated

          // 调用求值函数，中途收集依赖
          const value = computeFn()

          // 完成求值后，清空标记
          Dep = null

          // 最终返回的 getter 结果
          return value
        },
        // 计算属性无法 set
        set() { }

      })

    }

    // 通过 getter 与 setter 定义出一个 reactive
    function defineReactive(obj, key) {

      let val = obj[key];

      // 在此标记哪些 computed 依赖了该 reactive
      const deps = []


      Object.defineProperty(obj, key, {
        // 为 reactive 求值时，收集其依赖
        get() {
          console.log('aaaa')
          // 返回 val 值作为 getter 求值结果
          return val;
        },

        // 为 reactive 赋值时，更新所有依赖它的计算属性
        set(newValue) {
          // 在 setter 中更新值
          val = newValue

          // 更新值后触发所有 computed 依赖更新
          // deps.forEach(changeFn => changeFn())
        }

      })
      console.log(999, deps)

    }

    console.log(ageObj.age, ageObj.age, ageObj.age)
  </script>
</body>

</html>